package cn.tedu.mall.front.service.impl;

import cn.tedu.mall.front.mappers.FrontCategoryMapper;
import cn.tedu.mall.front.service.IFrontCategoryService;
import cn.tedu.mall.pojo.front.entity.FrontCategoryEntity;
import cn.tedu.mall.pojo.front.vo.FrontCategoryTreeVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class FrontCategoryServiceImpl implements IFrontCategoryService {

    private static final String FRONT_CATEGORY_TREE_KEY = "front:category:tree";

    private final FrontCategoryMapper frontCategoryMapper;
    private final RedisTemplate<String, Object> redisTemplate;

    @Autowired
    public FrontCategoryServiceImpl(FrontCategoryMapper frontCategoryMapper, RedisTemplate<String, Object> redisTemplate) {
        this.frontCategoryMapper = frontCategoryMapper;
        this.redisTemplate = redisTemplate;
    }

    @Override
    public FrontCategoryTreeVO<FrontCategoryEntity> categoryTree() {
        // 引入redis缓存，该数据不会频繁变动，而且没有必要引入超时
        ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
        Object o = valueOperations.get(FRONT_CATEGORY_TREE_KEY);
        if (o == null) {
            List<FrontCategoryEntity> frontCategoryEntityList = frontCategoryMapper.selectAll();
            FrontCategoryTreeVO<FrontCategoryEntity> frontCategoryTreeVO = initTree(frontCategoryEntityList);
            valueOperations.set(FRONT_CATEGORY_TREE_KEY, frontCategoryTreeVO);
            return frontCategoryTreeVO;
        }
        return (FrontCategoryTreeVO) o;
    }

    private FrontCategoryTreeVO<FrontCategoryEntity> initTree(List<FrontCategoryEntity> frontCategoryEntityList) {
        /*
         * 参数是包含所有分类的数组集合
         * 使用一个Map对象 key值是分类的id，value值是一个list集合
         * 如果这个id对应的分类是父级分类
         * 那么这个list集合中就包含了这个分类的所有子级分类
         */
        Map<Long, List<FrontCategoryEntity>> categoryMap = new HashMap<>();
        log.debug("当前拿到分类个数：{}", frontCategoryEntityList.size());
        for (FrontCategoryEntity frontCategoryEntity : frontCategoryEntityList) {
            // 父级分类的id
            Long parentId = frontCategoryEntity.getParentId();
            // 判断map是否有这个key值，有则添加，没有则构建初始化数据
            if (categoryMap.containsKey(parentId)) {
                // 说明这个分类是父级分类
                categoryMap.get(parentId).add(frontCategoryEntity);
            } else {
                // 说明这个分类是子级分类
                List<FrontCategoryEntity> list = new java.util.ArrayList<>();
                list.add(frontCategoryEntity);
                categoryMap.put(parentId, list);
            }
        }
        // 当前map中保存了所有同一父级分类下的子级集合，但是没有办法区分2级分类，3级分类
        // 1级分类key=0 根据一级分类集合遍历找到二级分类，嵌套遍历二级分类找到三级分类
        // 准备返回对象
        FrontCategoryTreeVO<FrontCategoryEntity> frontCategoryTreeVO = new FrontCategoryTreeVO<>();
        // 拿到一级分类
        List<FrontCategoryEntity> firstLevelCategories = categoryMap.get(0L);
        // 遍历一级分类，封装二级分类的list集合
        for (FrontCategoryEntity firstLevelCategory : firstLevelCategories) {
            // 拿到每个一级分类的id
            Long firstLevelId = firstLevelCategory.getId();
            // 到map中去取这个id对应的下级分类集合
            List<FrontCategoryEntity> secondLevelCategories = categoryMap.get(firstLevelId);
            firstLevelCategory.setChildrens(secondLevelCategories);
            // 嵌套循环遍历二级分类，封装三级分类list集合
            for (FrontCategoryEntity secondLevelCategory : secondLevelCategories) {
                // 拿到每个二级分类的id
                Long secondLevelId = secondLevelCategory.getId();
                // 到map中去取这个id对应的下级分类集合
                List<FrontCategoryEntity> thirdLevelCategories = categoryMap.get(secondLevelId);
                secondLevelCategory.setChildrens(thirdLevelCategories);
            }
        }
        frontCategoryTreeVO.setCategories(firstLevelCategories);
        return frontCategoryTreeVO;
    }
}
